package com.jevons.geo_lib.utils;

import com.mapbox.geojson.Feature;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.MultiLineString;
import com.mapbox.geojson.MultiPoint;
import com.mapbox.geojson.MultiPolygon;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.turf.TurfMeasurement;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.locationtech.jts.io.geojson.GeoJsonReader;
import org.locationtech.jts.io.geojson.GeoJsonWriter;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import mil.nga.sf.geojson.FeatureConverter;

/**
 * Copyright 2020 JxGIS
 *
 * @file MapUtils
 * @auth linaisheng
 * Created on 2020/8/21.
 * Description：
 */
public class MapDataUtils {


    //计算面积
    public static double calculateArea(List<Point> var0) {
        List<List<Point>> points = new ArrayList<>();
        points.add(var0);
        return TurfMeasurement.area(Polygon.fromLngLats(points));
    }


    //转换为wkt
    public static String convert2Wkt(String type, String coordinates) throws JSONException {

        //"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"
        StringBuffer wkt = new StringBuffer();

        JSONArray jsonArray = new JSONArray(coordinates);

        type = type.toUpperCase();
        switch (type) {
            case "POINT":
                //[100.0, 0.0]
                wkt.append("POINT(").append(jsonArray.getString(0)).append(" ")
                        .append(jsonArray.getString(1)).append(")");
                break;
            case "MULTIPOINT":
                //[
                //        [100.0, 0.0],
                //        [101.0, 1.0]
                //    ]
                wkt.append("MULTIPOINT(");
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONArray point = jsonArray.getJSONArray(i);
                    wkt.append(point.getString(0)).append(" ").append(point.get(1)).append(",");
                }
                wkt.deleteCharAt(wkt.length() - 1);
                wkt.append(")");
                break;
            case "LINESTRING":
                //和multipoint结构一样
                //[
                //                [101.0, 0.0],
                //                [102.0, 1.0]
                //            ]
                wkt.append("LINESTRING").append(wktLineString(jsonArray));
                break;
            case "MULTILINESTRING":
                //[
                //        [
                //            [100.0, 0.0],
                //            [101.0, 1.0]
                //        ],
                //        [
                //            [102.0, 2.0],
                //            [103.0, 3.0]
                //        ]
                //    ]
                wkt.append("MULTILINESTRING(");
                for (int i = 0; i < jsonArray.length(); i++) {
                    wkt.append("").append(wktLineString(jsonArray.getJSONArray(i))).append("").append(",");
                }
                wkt.deleteCharAt(wkt.length() - 1);
                wkt.append(")");
                break;
            case "POLYGON":
                //POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2))
                //"coordinates": [
                //            [
                //                [-180.0, 10.0],
                //                [20.0, 90.0],
                //                [180.0, -5.0],
                //                [-30.0, -90.0]
                //            ]
                //        ]
                wkt.append("POLYGON").append(wktPolygon(jsonArray));
                break;
            case "MULTIPOLYGON":
                //解析为多个polygon
                wkt.append("MULTIPOLYGON(");
                for (int i = 0; i < jsonArray.length(); i++) {
                    wkt.append(wktPolygon(jsonArray.getJSONArray(i))).append(",");
                }
                wkt.deleteCharAt(wkt.length() - 1);
                wkt.append(")");
                break;
        }

        return wkt.toString();
    }

    private static String wktLineString(JSONArray jsonArray) throws JSONException {

        StringBuffer wkt = new StringBuffer();

        wkt.append("(");
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONArray point = jsonArray.getJSONArray(i);
            wkt.append(point.getString(0)).append(" ").append(point.get(1)).append(",");
        }
        wkt.deleteCharAt(wkt.length() - 1);
        wkt.append(")");

        return wkt.toString();
    }

    private static String wktPolygon(JSONArray jsonArray) throws JSONException {

        StringBuffer wkt = new StringBuffer();

        wkt.append("(");
        for (int i = 0; i < jsonArray.length(); i++) {
            //是一组组的LineString
            wkt.append("(");
            JSONArray lineString = jsonArray.getJSONArray(i);
            for (int j = 0; j < lineString.length(); j++) {
                JSONArray pointArray = lineString.getJSONArray(j);
                wkt.append(pointArray.getString(0)).append(" ").append(pointArray.getString(1))
                        .append(",");

                //如果该数组不是闭合的，使其闭合
                if (j == lineString.length() -1) {
                    JSONArray firstPointArray = lineString.getJSONArray(0);

                    if (!pointArray.getString(0).equals(firstPointArray.getString(0))
                            || !pointArray.getString(1).equals(firstPointArray.getString(1))) {
                        //闭合
                        wkt.append(firstPointArray.getString(0)).append(" ").append(firstPointArray.getString(1))
                                .append(",");
                    }
                }
            }

            if (wkt.length() > 0) {
                //删除最后一个逗号
                wkt.deleteCharAt(wkt.length() - 1);
            }
            wkt.append("),");
        }
        if (wkt.length() > 0) {
            wkt.deleteCharAt(wkt.length() - 1);
        }
        wkt.append(")");

        return wkt.toString();
    }


    public static String wktToJson(String wkt) {
        String json = null;
        try {
            WKTReader reader = new WKTReader();
            Geometry geometry = reader.read(wkt);
            StringWriter writer = new StringWriter();
            GeoJsonWriter g = new GeoJsonWriter(18);
            g.write(geometry, writer);
            json = writer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return json;
    }

    public static Feature wktToFeature(String wkt) {
        com.mapbox.geojson.Geometry geometry = wktToGeometry(wkt);
        if (geometry != null) {
            return Feature.fromGeometry(geometry);
        }
        return null;
    }

    public static com.mapbox.geojson.Geometry wktToGeometry(String wkt) {
        String json = wktToJson(wkt);
        if (StringUtils.isNotEmpty(json)) {
            return geoJsonToGeometry(json);
        }
        return null;
    }


    public static com.mapbox.geojson.Geometry geoJsonToGeometry(String json) {
        if (StringUtils.isNotEmpty(json)) {
            try {
                JSONObject jsonObject = new JSONObject(json);
                String type = jsonObject.getString("type");

                com.mapbox.geojson.Geometry geometry = null;
                switch (type) {
                    case "Point":
                        geometry = Point.fromJson(json);
                        break;
                    case "MultiPoint":
                        geometry = MultiPoint.fromJson(json);
                        break;
                    case "LineString":
                        geometry = LineString.fromJson(json);
                        break;
                    case "MultiLineString":
                        geometry = MultiLineString.fromJson(json);
                        break;
                    case "Polygon":
                        geometry = Polygon.fromJson(json);
                        break;
                    case "MultiPolygon":
                        geometry = MultiPolygon.fromJson(json);
                        break;
                }
                if (geometry != null) {
                    return geometry;
                }

            } catch (Exception e) {}

        }

        return null;
    }

    public static String jsonToWkt(String json) {
        try {
            GeoJsonReader reader = new GeoJsonReader();
            Geometry geometry = reader.read(json);
            WKTWriter writer = new WKTWriter();
            String wkt = writer.write(geometry);
            return wkt;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Feature gpkgGeometryToFeature(mil.nga.sf.Geometry geo) {
        String geoJson = FeatureConverter.toStringValue(geo);
        com.mapbox.geojson.Geometry geometry = geoJsonToGeometry(geoJson);
        return Feature.fromGeometry(geometry);

    }

}
